﻿
using System;
using System.Collections.Generic;
using System.Threading;

namespace Frame.Model
{
    public class PackingManager
    {
        private static PackingManager s_singleton = default(PackingManager);
        private static object s_objectLock = new object();
        public static PackingManager Instance
        {
            get
            {
                if (PackingManager.s_singleton == null)
                {
                    object obj;
                    Monitor.Enter(obj = PackingManager.s_objectLock);//加锁防止多线程创建单例
                    try
                    {
                        if (PackingManager.s_singleton == null)
                        {
                            PackingManager.s_singleton = ((default(PackingManager) == null) ? Activator.CreateInstance<PackingManager>() : default(PackingManager));//创建单例的实例
                        }
                    }
                    finally
                    {
                        Monitor.Exit(obj);
                    }
                }
                return PackingManager.s_singleton;
            }
        }

        //private Dictionary<string, int> m_MaxTypeDic;
        //private Dictionary<string, int> m_MinTypeDic;
        private Dictionary<string, List<VartableBase>> m_ObjectPoolDic;

        public PackingManager()
        {
            m_ObjectPoolDic = new Dictionary<string, List<VartableBase>>();
        }

        public object CreatePackValue<T>(T t)
        {
            Type type = typeof(T);
            string typeName = type.Name;
            if (type.IsValueType)
            {
                return NewVartable<T>(typeName, t);
            }
            return t;

        }
        public bool TryGetValue<T>(object packValue, out T t)
        {
            Type type = typeof(T);
            string typeName = type.Name;
            if (packValue is VartableBase)
            {
                VartableBase vb = (VartableBase)packValue;
                if (!vb.hasRecycle && vb.typeName == typeName)
                {
                    t = ((Vartable<T>)vb).Value;
                    StoreVartable(vb);
                    return true;
                }
                StoreVartable(vb);
            }
            else if (packValue.GetType().Name == type.Name)
            {
                t = (T)packValue;
                return true;
            }
            t = default(T);
            return false;
        }

        private VartableBase NewVartable<T>(string typeName, T t)
        {
            Vartable<T> vb;
            if (!m_ObjectPoolDic.ContainsKey(typeName))
            {
                m_ObjectPoolDic[typeName] = new List<VartableBase>();
            }
            List<VartableBase> vlist = m_ObjectPoolDic[typeName];
            if (vlist.Count == 0)
            {
                vb = new Vartable<T>();
                vb.Value = t;
            }
            else
            {
                vb = (Vartable<T>)vlist[0];
                vlist.Remove(vb);
                return vb;
            }
            vb.typeName = typeName;
            vb.hasRecycle = false;
            return vb;
        }

        private void StoreVartable(VartableBase vb)
        {
            if (!m_ObjectPoolDic.ContainsKey(vb.typeName))
            {
                m_ObjectPoolDic[vb.typeName] = new List<VartableBase>();
            }
            List<VartableBase> vlist = m_ObjectPoolDic[vb.typeName];
            if (!vlist.Contains(vb))
                vlist.Add(vb);
            vb.hasRecycle = true;
        }

        //private class VartableBool : Vartable<bool>
        //{
        //    public override bool Parse(VartableBase vb)
        //    {
        //        switch (vb.typeName)
        //        {
        //            case "SByte":
        //                sbyte sbv = ((Vartable<sbyte>)vb).Value;
        //                return ((sbv + 1) % 2) == 0?true:false;
        //            case "Byte":
        //                byte bv = ((Vartable<byte>)vb).Value;
        //                break;
        //            case "Int16":
        //                short st = ((Vartable<short>)vb).Value;
        //                break;
        //            case "UInt16":
        //                ushort ust = ((Vartable<ushort>)vb).Value;
        //                break;
        //            case "Int32":
        //                int it = ((Vartable<int>)vb).Value;
        //                break;
        //            case "UInt32":
        //                uint uit = ((Vartable<uint>)vb).Value;
        //                break;
        //            case "Int64":
        //                long lg = ((Vartable<long>)vb).Value;
        //                break;
        //            case "UInt64":
        //                ulong ulg = ((Vartable<ulong>)vb).Value;
        //                break;
        //            case "Char":
        //                char c = ((Vartable<char>)vb).Value;
        //                break;
        //            case "Single":
        //                float ft = ((Vartable<float>)vb).Value;
        //                break;
        //            case "Double":
        //                double db = ((Vartable<double>)vb).Value;
        //                break;
        //            case "Boolean":
        //                return((VartableBool)vb).Value;
        //            case "Decimal":
        //                decimal dl = ((Vartable<decimal>)vb).Value;
        //                break;
        //        }
        //    }

        //    public override bool TryParse(VartableBase vb, out bool t)
        //    {
        //        throw new NotImplementedException();
        //    }
        //}
        private class Vartable<T> : VartableBase
        {
            public T Value;
            //public abstract T Parse(VartableBase vb);
            //public abstract bool TryParse(VartableBase vb,out T t);
        }
        private abstract class VartableBase
        {
            public bool hasRecycle;
            public string typeName;
        }
    }

    public abstract class ParamObject
    {
       
    }
    public class GenericParamObject<T>: ParamObject
    {

    }
}
